package com.ruicar.afs.jobadmin.service.impl;

import com.ruicar.afs.cloud.common.job.core.biz.AdminBiz;
import com.ruicar.afs.cloud.common.job.core.biz.model.HandleCallbackParam;
import com.ruicar.afs.cloud.common.job.core.biz.model.RegistryParam;
import com.ruicar.afs.cloud.common.job.core.biz.model.ReturnT;
import com.ruicar.afs.cloud.common.job.core.handler.IJobHandler;
import com.ruicar.afs.jobadmin.mapper.AfsJobInfoMapper;
import com.ruicar.afs.jobadmin.core.model.AfsJobInfo;
import com.ruicar.afs.jobadmin.core.model.AfsJobLog;
import com.ruicar.afs.jobadmin.core.thread.JobTriggerPoolHelper;
import com.ruicar.afs.jobadmin.core.trigger.TriggerTypeEnum;
import com.ruicar.afs.jobadmin.core.util.I18nUtil;
import com.ruicar.afs.jobadmin.mapper.AfsJobGroupMapper;
import com.ruicar.afs.jobadmin.mapper.AfsJobLogMapper;
import com.ruicar.afs.jobadmin.mapper.AfsJobRegistryMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;

/**
 * The type AdminBizImpl
 * <p>Description: </p>
 *
 * @author Fzero
 * @version 1.0
 * @date Created on 2020.06.13 14:17:12
 * @since 1.0
 */
@Service
public class AdminBizImpl implements AdminBiz {
    /**
     * Logger
     * <p>Description: </p>
     */
    private static Logger logger = LoggerFactory.getLogger(AdminBizImpl.class);

    /**
     * Afs job log mapper
     * <p>Description: </p>
     */
    @Resource
    public AfsJobLogMapper afsJobLogMapper;
    /**
     * Afs job info mapper
     * <p>Description: </p>
     */
    @Resource
    private AfsJobInfoMapper afsJobInfoMapper;
    /**
     * Afs job registry mapper
     * <p>Description: </p>
     */
    @Resource
    private AfsJobRegistryMapper afsJobRegistryMapper;
    /**
     * Afs job group mapper
     * <p>Description: </p>
     */
    @Resource
    private AfsJobGroupMapper afsJobGroupMapper;


    /**
     * Callback return t
     *
     * @param callbackParamList callback param list
     * @return the return t
     */
    @Override
    public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
        for (HandleCallbackParam handleCallbackParam : callbackParamList) {
            ReturnT<String> callbackResult = callback(handleCallbackParam);
            logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
                    (callbackResult.getCode() == IJobHandler.SUCCESS.getCode() ? "success" : "fail"), handleCallbackParam, callbackResult);
        }

        return ReturnT.SUCCESS;
    }

    /**
     * Callback return t
     *
     * @param handleCallbackParam handle callback param
     * @return the return t
     */
    private ReturnT<String> callback(HandleCallbackParam handleCallbackParam) {
        // valid log item
        AfsJobLog log = afsJobLogMapper.load(handleCallbackParam.getLogId());
        if (log == null) {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
        }
        if (log.getHandleCode() > 0) {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback.");     // avoid repeat callback, trigger child job etc
        }

        // trigger success, to trigger child job
        String callbackMsg = null;
        if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
            AfsJobInfo afsJobInfo = afsJobInfoMapper.loadById(log.getJobId());
            if (afsJobInfo != null && afsJobInfo.getChildJobId() != null && afsJobInfo.getChildJobId().trim().length() > 0) {
                callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<< </span><br>";

                String[] childJobIds = afsJobInfo.getChildJobId().split(",");
                for (int i = 0; i < childJobIds.length; i++) {
                    int childJobId = (childJobIds[i] != null && childJobIds[i].trim().length() > 0 && isNumeric(childJobIds[i])) ? Integer.valueOf(childJobIds[i]) : -1;
                    if (childJobId > 0) {

                        JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null);
                        ReturnT<String> triggerChildResult = ReturnT.SUCCESS;

                        // add msg
                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
                                (i + 1),
                                childJobIds.length,
                                childJobIds[i],
                                (triggerChildResult.getCode() == ReturnT.SUCCESS_CODE ? I18nUtil.getString("system_success") : I18nUtil.getString("system_fail")),
                                triggerChildResult.getMsg());
                    } else {
                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
                                (i + 1),
                                childJobIds.length,
                                childJobIds[i]);
                    }
                }

            }
        }

        // handle msg
        StringBuffer handleMsg = new StringBuffer();
        if (log.getHandleMsg() != null) {
            handleMsg.append(log.getHandleMsg()).append("<br>");
        }
        if (handleCallbackParam.getExecuteResult().getMsg() != null) {
            handleMsg.append(handleCallbackParam.getExecuteResult().getMsg());
        }
        if (callbackMsg != null) {
            handleMsg.append(callbackMsg);
        }

        // success, save log
        log.setHandleTime(new Date());
        log.setHandleCode(handleCallbackParam.getExecuteResult().getCode());
        log.setHandleMsg(handleMsg.toString());
        afsJobLogMapper.updateHandleInfo(log);

        return ReturnT.SUCCESS;
    }

    /**
     * Is numeric boolean
     *
     * @param str str
     * @return the boolean
     */
    private boolean isNumeric(String str) {
        try {
            int result = Integer.valueOf(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * Registry return t
     *
     * @param registryParam registry param
     * @return the return t
     */
    @Override
    public ReturnT<String> registry(RegistryParam registryParam) {

        // valid
        if (!StringUtils.hasText(registryParam.getRegistryGroup())
                || !StringUtils.hasText(registryParam.getRegistryKey())
                || !StringUtils.hasText(registryParam.getRegistryValue())) {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
        }

        int ret = afsJobRegistryMapper.registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
        if (ret < 1) {
            afsJobRegistryMapper.registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());

            // fresh
            freshGroupRegistryInfo(registryParam);
        }
        return ReturnT.SUCCESS;
    }

    /**
     * Registry remove return t
     *
     * @param registryParam registry param
     * @return the return t
     */
    @Override
    public ReturnT<String> registryRemove(RegistryParam registryParam) {

        // valid
        if (!StringUtils.hasText(registryParam.getRegistryGroup())
                || !StringUtils.hasText(registryParam.getRegistryKey())
                || !StringUtils.hasText(registryParam.getRegistryValue())) {
            return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
        }

        int ret = afsJobRegistryMapper.registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
        if (ret > 0) {

            // fresh
            freshGroupRegistryInfo(registryParam);
        }
        return ReturnT.SUCCESS;
    }

    /**
     * Fresh group registry info *
     *
     * @param registryParam registry param
     */
    private void freshGroupRegistryInfo(RegistryParam registryParam) {
        // Under consideration, prevent affecting core tables
    }

}
